using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using System.Xml;


namespace OWED.Document
{
    [TestFixture]
    public class TestAbsolutePath
    {

        private XmlDocument simpleXML;

        [SetUp]
        public void Init() {
            simpleXML = new XmlDocument();
            simpleXML.LoadXml("<book>" + 
                "<chapter>" +
                    "<para>" +
                        "This is a paragraph!" +
                    "</para>" + 
                "</chapter>" +
            "</book>");
        }
             


        [Test]
        public void TestConstructor()
        {
            AbsolutePath a = new AbsolutePath("/note/2/to/0/");
            Assert.IsTrue(true);
        }

        [Test]
        public void TestBasicLookup()
        {
            AbsolutePath path = new AbsolutePath(simpleXML.FirstChild);

            Assert.AreEqual(path.ToString(), "#document/0/book/0/");
        }

        [Test]
        public void TestBasicLookup2()
        {
            AbsolutePath path = new AbsolutePath(simpleXML.FirstChild.FirstChild);
            Assert.AreEqual(path.ToString(), "#document/0/book/0/chapter/0/");
        }

        [Test]
        public void TestBasicLookup3() 
        {
            AbsolutePath path = new AbsolutePath(simpleXML.FirstChild.FirstChild.FirstChild);
            Assert.AreEqual("#document/0/book/0/chapter/0/para/0/", path.ToString());
        }

        [Test]
        public void TestBasicLookup4()
        {
            AbsolutePath path = new AbsolutePath(simpleXML.FirstChild.FirstChild.FirstChild.FirstChild);
            Assert.AreEqual("#document/0/book/0/chapter/0/para/0/#text/0/", path.ToString());
            Assert.AreEqual(path.getNode(simpleXML).InnerText, "This is a paragraph!", "Testing pcdata lookup");
        }

        [Test]
        public void TestBasicSearch()
        {
            AbsolutePath path = new AbsolutePath("#document/0/");
            XmlNode node = path.getNode(simpleXML);
            Assert.AreEqual(node, simpleXML);
        }

        [Test]
        public void TestBasicSearch2()
        {
            AbsolutePath path = new AbsolutePath("#document/0/book/0/");
            XmlNode node = path.getNode(simpleXML);
            Assert.AreEqual(simpleXML.FirstChild, node);
        }

        [Test]
        public void TestBasicSearch3()
        {
            AbsolutePath path = new AbsolutePath("#document/0/book/0/chapter/0/");
            XmlNode node = path.getNode(simpleXML);
            Assert.AreEqual(simpleXML.FirstChild.FirstChild, node);
        }

        [Test]
        public void TestConstructorBuilding()
        {
            AbsolutePath path = new AbsolutePath("#document/0");
            AbsolutePath path2 = new AbsolutePath(path, "book", 1);

            AbsolutePath path3 = new AbsolutePath("#document/0/book/1");
            Assert.AreEqual(path2.ToString(), path3.ToString(), "Extend constructor");

            AbsolutePath pathminus = new AbsolutePath(path3, 1);
            Assert.AreEqual(path.ToString(), pathminus.ToString(), "Delete constructor");

            AbsolutePath large = new AbsolutePath("#document/0/book/1/chapter/3");
            AbsolutePath shorter = new AbsolutePath(large, 2);
            Assert.AreEqual(path.ToString(), shorter.ToString(), "Delete constructor");

            Assert.AreNotEqual(path.ToString(), large.ToString(), "Sanity check");
        }

        [Test]
        public void TestChangeAtoms_AddTag()
        { //this actually tests DeleteTag too.
            XmlDocument mydoc = simpleXML.Clone() as XmlDocument;
            Assert.IsNotNull(mydoc, "Sanity check");

            XmlElement para = mydoc.CreateElement("para");

            AddTag addtag = new AddTag(
                new AbsolutePath("#document/0/book/0/chapter/0"), para, 1);
            addtag.Apply(mydoc);

            XmlDocument manual = simpleXML.Clone() as XmlDocument;
            manual.ChildNodes.Item(0).ChildNodes.Item(0).InsertBefore(manual.ImportNode(para, true),
                manual.ChildNodes.Item(0).ChildNodes.Item(0).ChildNodes.Item(0));
            Assert.AreEqual(manual.OuterXml, mydoc.OuterXml, "Checking that apply works");

            addtag.Reverse(mydoc);
            Assert.AreEqual(simpleXML.OuterXml, mydoc.OuterXml, "Checking that reverse works");
        }

        [Test]
        public void TestChangeAtoms_ChangeTag()
        {
            XmlDocument mydoc = simpleXML.Clone() as XmlDocument;
            Assert.IsNotNull(mydoc, "Sanity check");
            XmlText txt = mydoc.CreateTextNode("different text");
            XmlNode old = mydoc.FirstChild.SelectSingleNode("/book/chapter/para").FirstChild;
            Assert.IsNotNull(old);
            ChangeTag ct = new ChangeTag(new AbsolutePath("#document/0/book/0/chapter/0/para/0/#text/0"),
                                        old,
                                        txt);
            ct.Apply(mydoc);
            Assert.AreNotEqual(mydoc.OuterXml, simpleXML.OuterXml, "Did it actually change it?");
            ct.Reverse(mydoc);
            Assert.AreEqual(mydoc.OuterXml, simpleXML.OuterXml, "Did it rever is?");
        }


        [Test]
        public void TestChangeAtoms_Serialization()
        {
            AbsolutePath path = new AbsolutePath("#document/0/book/0/chapter/0");
            DeleteTag dtag = new DeleteTag(path,
                                        simpleXML.SelectSingleNode("/book/chapter"));

            String ser = dtag.Serialize();

            ChangeAtom atom = ChangeAtom.FromSerialized(ser);
            Assert.IsNotNull(atom as DeleteTag, "checking if it gets the right type");
            Assert.AreEqual(path.ToString(), (atom as DeleteTag).Path.ToString());
            Assert.AreEqual("chapter", (atom as DeleteTag).Node.Name);


            XmlNode added = simpleXML.CreateElement("something");
            AddTag atag = new AddTag(path, added, 0);
            ser = atag.Serialize();
            atom = ChangeAtom.FromSerialized(ser);
            Assert.IsNotNull(atom as AddTag, "checking if it gets the right type");
            Assert.AreEqual(path.ToString(), (atom as AddTag).Path.ToString());
            Assert.AreEqual("something", (atom as AddTag).Node.Name);



            XmlNode changed = simpleXML.CreateElement("another");
            ChangeTag ctag = new ChangeTag(path, added, changed);
            ser = ctag.Serialize();
            atom = ChangeAtom.FromSerialized(ser);
            Assert.IsNotNull(atom as ChangeTag, "checking if it gets the right type");
            Assert.AreEqual(path.ToString(), (atom as ChangeTag).Path.ToString());
            Assert.AreEqual("something", (atom as ChangeTag).OldNode.Name);
            Assert.AreEqual("another", (atom as ChangeTag).NewNode.Name);
        }
    }
}
